Since the release of .NET 2.0, it has been possible to build partial class definitions using the partial keyword (see Chapter 5). Recall that this bit of syntax allows you to partition the full implementation of a type across multiple code files (or other locations, such as in memory). As long as each aspect of the partial type has the same fully qualified name, the end result is a single “normal” compiled class type in the assembly being constructed.
C# recycles the role of the partial keyword in that it can now be applied on the method level. In a nutshell, this allows you to prototype a method in one file, yet implement it in another file. If you have a C++ background, this might remind you of a C++ header/implementation file; however, C# partial methods have a number of important restrictions:
Even stranger is the fact that a partial method may or may not be emitted into the compiled assembly! Let’s see an example to clarify matters.
To see the implications of defining a partial method, create a new Console Application project named PartialMethods. Now, define a new class named CarLocator within a C# file named CarLocator.cs:
// CarLocator.cs partial class CarLocator { // This member will always be part of the // CarLocator class. public bool CarAvailableInZipCode(string zipCode) { // This call *may* be part of this method // implementation. VerifyDuplicates(zipCode); // Assume some interesting database logic // here... return true; } // This member *may* be part of the CarLocator class! partial void VerifyDuplicates(string make); }
Notice that the VerifyDuplicates() method has been defined with the partial modifier and does not define a method body within this file. Also notice that the CarAvailableInZipCode() method is making a call to VerifyDuplicates() within its implementation.
If you were to compile this application as it now stands and open the compiled assembly in a tool such as ildasm.exe or reflector.exe, you would find no trace of the VerifyDuplicates() method in the CarLocator class, and no trace of the call to VerifyDuplicates() within CarAvailableInZipCode()! With the project as it now stands, you really authored the following definition of the CarLocator class as far as the compiler is concerned:
internal class CarLocator { public bool CarAvailableInZipCode(string zipCode) { return true; } }
The reason for this strange stripping away of code has to do with the fact that the partial VerifyDuplicates() method was never given a true implementation. If you were to now add a new file to your project (named perhaps CarLocatorImpl.cs) that defined the remainder of the partial method:
// CarLocatorImpl.cs partial class CarLocator { partial void VerifyDuplicates(string make) { // Assume some expensive data validation // takes place here... } }
you would find that the full scope of the CarLocator class is taken into account at compile time, as shown in the following approximate C# code:
internal class CarLocator { public bool CarAvailableInZipCode(string zipCode) { this.VerifyDuplicates(zipCode); return true; } private void VerifyDuplicates(string make) { } }
As you can see, when a method is defined with the partial keyword, the compiler will determine if it should be emitted into the assembly based on whether the method has a method body or is simply an empty signature. If there is no method body, all traces of the method (invocations, metadata descriptions, prototypes) are stripped out during the compilation cycle.
In some ways, C# partial methods are a strongly typed version of conditional code compilation (via the #if, #elif, #else, and #endif preprocessor directives). The major difference, however, is that a partial method will be completely ignored during the compilation cycle (regardless of build settings) if there is not a supporting implementation.
Given the restrictions that come with partial methods, most notably that they must be implicitly private and always return void, it is hard to see many useful applications of this new language feature. Truth be told, out of all of the language features of C#, partial methods seem among those likely to be used the least.
In the current example, the VerifyDuplicates() method was marked as partial for illustrative purposes. However, imagine that this method, if implemented, had to perform some very intensive calculations.
By marking this method with the partial modifier, other class builders have the option of providing implementation details if they so choose. In this case, partial methods provide a cleaner solution than using preprocessor directives, supplying “dummy” implementations to virtual methods, or throwing NotImplementedException objects.
The most common use of this syntax is to define what are termed lightweight events. This technique enables class designers to provide method hooks, similar to event handlers, that developers may choose to implement or not. As a naming convention, such lightweight event-handling methods take an On prefix, for example:
// CarLocator.EventHandler.cs partial class CarLocator { public bool CarAvailableInZipCode(string zipCode) { ... OnZipCodeLookup(zipCode); return true; } ... // A "lightweight" event handler. partial void OnZipCodeLookup(string make); }
If any class builders wish to be informed when the CarAvailableInZipCode() method has been called, they can provide an implementation of the OnZipCodeLookup() method. If they do not care, they simply do nothing.
Source Code The PartialMethods project can be found under the Chapter 12 subdirectory.